home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************
- * file: FAXSCALE.C
- * purpose: Minimalist scaler. Scales images over a range of
- * 3% to 3200% with a worst case precision of 1/32. This code
- * was designed to minimize data, stack and code requirements
- * while being reasonably fast and accurate. Since the intended
- * use is in fax machine, the scaled lines are clipped or white
- * filled to FAX_WIDTH bytes. Refer to the function headers for
- * more detailed information. Image lines follow the usual
- * monochromatic format of 1 being black, 0 being white and
- * bit 7 of each byte being the leftmost pixel. This code is
- * an algorithm test bench. The production version is in
- * assembly.
- * environment: ANSI C tested with Borland 4.0, Zortech 3.1 and
- * MSC 5.1
- * contains:
- * init_fax_scale() - initializes the scaler
- * scale_fax_line() - scales a single image line
- * history:
- * 06-09-92 - initial code
- * 04-04-94 - polished, reformatted, retested, condensed
- **************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
-
-
- /* data types and defines */
-
- typedef unsigned long ROTATOR; /* rotator type sets scaling
- * range and precision */
- #define PRECISION (4 * 8) /* ANSI doesn't allow sizeof(ROTATOR)
- * in preprocessor */
- #define SCALE_MAX (PRECISION * 100) /* upper limit of scaler in % */
- #define SCALE_MIN (100 / PRECISION) /* lower limit of scaler in % */
- #define FAX_WIDTH 216 /* hardwired byte width of a fax line */
-
- /* rotate instruction, just a kludge until assembly */
- #define _ror(val) (val) = ((val) >> 1 | (val) << (PRECISION-1))
-
-
- /* ROMmable const data */
- /* sequential increase in bits per byte: do not change
- * without looking closely at init_rotator() */
- static const unsigned char pattern[] =
- {0x00,0x10,0x44,0x94,0xaa,0xda,0xee,0xfe,0xff,0xff};
-
-
- /* RAM data */
- static ROTATOR x_rotator; /* rotating horizontal pattern */
- static ROTATOR y_rotator; /* rotating vertical pattern */
- static unsigned int source_width; /* number of bytes in a source line */
- static unsigned char x_base; /* n/8 basis for x_rotator */
- static unsigned char y_base; /* n/8 basis for y_rotator */
-
-
- /* local functions */
- static int init_rotator(int scale,ROTATOR *rotator,unsigned char *base);
-
-
- /************************************************
- * function: int init_fax_scale(int x_scale,int y_scale,unsigned int source_byte_width)
- * Validate the scaling ranges and initialize the scaler. You
- * must call this function first before you can use the scaler.
- * parameters: horizontal and vertical scaling in percent followed
- * by the byte width of a source line.
- * returns: 1 if Ok or 0 if either scale is out of range
- ************************************************/
- int init_fax_scale(int x_scale,int y_scale,unsigned int source_byte_width)
- {
- if (!init_rotator(x_scale,&x_rotator,&x_base))
- return 0; /* set up x_rotator */
- if (!init_rotator(y_scale,&y_rotator,&y_base))
- return 0; /* set up y_rotator */
- source_width = source_byte_width; /* save width */
- if (((long)source_width * (long)x_scale) / 100L > FAX_WIDTH)
- source_width = FAX_WIDTH; /* clip to fax line */
- return 1;
- }
-
-
- /************************************************
- * function: static int init_rotator(int scale,ROTATOR *rotator,unsigned char *base)
- * local function calculates the rotator and basis.
- * parameters: scale factor in percent, pointer to rotator,
- * pointer to basis.
- * returns: 1 if Ok or 0 if scale is out of range
- ************************************************/
- static int init_rotator(int scale,ROTATOR *rotator,unsigned char *base)
- {
- unsigned int index,mix,i;
-
- /* check scaling range */
- if (scale < SCALE_MIN || scale > SCALE_MAX)
- return 0;
- /* set basis */
- *base = scale / 100;
- /* get index into pattern */
- scale %= 100;
- index = (scale * 8) / 100;
- /* How we mix 2 consecutive patterns to achieve balance.
- * Express it this way to handle round off. */
- mix = pattern[((((scale * 8) % 100) + 4) * 8) / 100];
- /* for each byte in the rotator, select an appropriate
- * pattern byte based on the index and the mix */
- *rotator = 0;
- for (i = sizeof(ROTATOR) ; i > 0 ; i--)
- {
- *rotator <<= 8;
- *rotator |= pattern[index + (mix & 0x01)];
- mix >>= 1;
- }
- assert((*rotator + *base) != 0);
- assert(*base <= PRECISION);
- return 1;
- }
-
-
- /************************************************
- * function: int scale_fax_line(unsigned char *dest, unsigned char *src)
- * Scale the line from src to dest. dest will always be FAX_WIDTH
- * wide even if it requires clipping or whiting out the tail. The
- * return value indicates the number of times to repeat the line.
- * A 0 return means skip it. This was done to keep buffer control in
- * the caller. Call scale_fax_line() once for each source line.
- * parameters: pointer to destination and source
- * returns: number of times to repeat the line (0 to PRECISION)
- ************************************************/
- int scale_fax_line(unsigned char *dest, unsigned char *src)
- {
- int y_repeat,x_repeat,i,bit;
- unsigned int accum,byte;
- unsigned char *start;
- ROTATOR rotator;
-
- /* get line repeat value and rotate to next */
- y_repeat = y_base + (y_rotator & 0x01);
- _ror(y_rotator);
- /* if anything to do */
- if (y_repeat)
- {
- rotator = x_rotator;
- for (i=source_width, accum=1, start=dest ; i > 0 ; i--, src++)
- { /* each byte in the source line */
- for (bit=8, byte=*src ; bit > 0 ; bit--)
- { /* for each bit in the byte */
- x_repeat = x_base + (rotator & 1);
- _ror(rotator); /* get repeat count and rotate */
- while (x_repeat--)
- { /* for each repeat */
- accum <<= 1; /* copy bit into accumulator */
- accum += ((byte & 0x80) != 0);
- if (accum & 0x100)
- { /* output a byte and reset sentinel */
- *dest++ = accum & 0xff;
- accum = 1;
- }
- }
- byte <<= 1;
- }
- }
- if (accum > 1)
- { /* handle fragment */
- while ((accum & 0x100) == 0)
- accum <<= 1;
- *dest++ = accum & 0xff;
- }
- while (dest < start + FAX_WIDTH)
- { /* white out tail */
- *dest++ = 0;
- }
- }
- return y_repeat;
- }
-